<!DOCTYPE html>

<html>
    <head>
        <meta charset="UTF-8">
        <title>MutationObserver</title>
        <style>
            .wrapper {
                padding: 10px;
                border: 1px solid blue;
                margin: 15px auto;
            }
            .target>* {
                border: 1px solid purple;
                margin: 10px auto;
            }
        </style>
    </head>
    <body>
        <div class="wrapper buttons">
            <button>启用观察者</button>
            <button>修改属性</button>
            <button>添加子元素</button>
            <button>替换子元素</button>
            <button>删除子元素</button>
            <button>关闭观察者</button>
        </div>
        <div class="wrapper target"></div>

        <script>
            (function(){

                // 当观察到变动时执行的回调函数
                const callback = function(mutations, observer) {
                    console.log( '\t微任务开始' );
                    mutations.forEach( m => {
                        if ( m.type === 'childList' ) {
                            console.log('\t新增、替换或删除子节点');
                        }
                        else if ( m.type === 'attributes' ) {
                            console.log( `\t属性${m.attributeName}被更改`);
                        }
                    });
                    console.log( '\t微任务结束' );
                };

                // 观察器的配置（需要观察什么变动）
                const config = { attributes: true, childList: true, subtree: true };

                // 创建一个观察器实例并传入回调函数
                const observer = new MutationObserver(callback);

                const click = (element, handler) =>{
                    element.addEventListener('click', handler, false);
                }
                // 确定被观察的目标元素
                const target = document.querySelector('.target');
                const btns = document.querySelectorAll('.buttons>button');

                // 启用观察者
                click( btns[0], evt => {
                    console.log( `宏任务:${evt.target.innerHTML}` );
                    // 开始观察目标节点
                    observer.observe( target, config );
                });

                // 修改属性
                click( btns[1], evt => {
                    console.log( `宏任务开始:${evt.target.innerHTML}` );
                    if( target.hasAttribute('title') ) {
                        target.removeAttribute('title');
                    } else {
                        target.setAttribute('title', '你点一个试试');
                    }
                    console.log( `宏任务结束:${evt.target.innerHTML}` );
                });

                // 添加子元素
                click( btns[2], evt => {
                    console.log( `宏任务开始:${evt.target.innerHTML}` );
                    let child = document.createElement('p');
                    child.innerHTML = new Date().toISOString();
                    target.appendChild(child);
                    console.log( `宏任务结束:${evt.target.innerHTML}` );
                });
                click( btns[3], evt => {
                    console.log( `宏任务开始:${evt.target.innerHTML}` );
                    let first = target.firstElementChild;
                    if( first ) {
                        let node = document.createElement('p');
                        let text = document.createTextNode( new Date().toISOString() );
                        node.appendChild(text);
                        target.replaceChild( node, first);
                    }
                    console.log( `宏任务结束:${evt.target.innerHTML}` );
                });
                click( btns[4], evt => {
                    console.log( `宏任务开始:${evt.target.innerHTML}` );
                    let last = target.lastElementChild;
                    if( last ) {
                        target.removeChild( last );
                    }
                    console.log( `宏任务结束:${evt.target.innerHTML}` );
                });

                // 关闭观察者
                click( btns[5], evt => {
                    console.log( `宏任务:${evt.target.innerHTML}` );
                    // 停止观察
                    observer.disconnect();
                });
            })();
        </script>
    </body>
</html>